/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.bopet.jocadv.core.datum;

import eu.bopet.jocadv.core.Element;
import eu.bopet.jocadv.core.Optimizable;
import eu.bopet.jocadv.core.Refreshable;
import eu.bopet.jocadv.core.VectorUtil;
import java.io.Serializable;
import java.util.Arrays;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;

/**
 * The class represent datum axes in three dimensional space
 *
 * @author bocskapeter
 */
public class Axis extends Element implements Serializable, Refreshable, Optimizable{

    // point on axis
    private Vector3D point;
    // axis diracetion
    private Vector3D direction;
    // axis representation is a line, defined by two points
    private final Vector3D[] line = new Vector3D[2];

    /**
     * Builds a new axis through the point in the x direction {1, 0, 0}
     *
     * @param point
     * @return Axis
     */
    public static Axis getDefaultX(Vector3D point) {
        Axis x = new Axis("X");
        x.setPoint(point);
        x.setDirection(Vector3D.PLUS_I);
        return x;
    }

    /**
     * Builds a new axis through the point in the y direction {0, 1, 0}
     *
     * @param point
     * @return Axis
     */
    public static Axis getDefaultY(Vector3D point) {
        Axis y = new Axis("Y");
        y.setPoint(point);
        y.setDirection(Vector3D.PLUS_J);
        return y;
    }

    /**
     * Builds a new axis through the point in the z direction {0, 0, 1}
     *
     * @param point
     * @return Axis
     */
    public static Axis getDefaultZ(Vector3D point) {
        Axis z = new Axis("Z");
        z.setPoint(point);
        z.setDirection(Vector3D.PLUS_K);
        return z;
    }

    /**
     * Default constructor
     *
     * @param name
     */
    public Axis(String name) {
        super(name);
    }

    /**
     * Gets the direction
     *
     * @return direction as Vector3D
     */
    public Vector3D getDirection() {
        return direction;
    }

    /**
     * Sets the direction
     *
     * @param direction as Vector3D
     */
    public void setDirection(Vector3D direction) {
        this.direction = direction;
    }

    /**
     * Gets the point :)
     *
     * @return point as Vector3D
     */
    public Vector3D getPoint() {
        return point;
    }

    /**
     * Sets the point :)
     *
     * @param point as Vector3D
     */
    public void setPoint(Vector3D point) {
        this.point = point;
    }

    /**
     * Gets the line
     *
     * @return line as Vector3D[]
     */
    public Vector3D[] getLine() {
        return line;
    }

    /**
     * Converts to String
     *
     * @return Sting
     */
    @Override
    public String toString() {
        return "\n Axis{" + super.toString() + "point=" + point + ", direction=" + direction + ", line=" + Arrays.toString(line) + '}';
    }

    /**
     * Refreshes the line according to the geometric limits
     *
     * @param max - Maximum as Vector3D
     * @param min - Minimum as Vector3D
     */
    @Override
    public void refreshLimits(Vector3D max, Vector3D min) {
        int likeVector = VectorUtil.getIndexOfBiggestAbsCoord(this.getDirection().toArray());
        double multiplicatorMax;
        double multiplicatorMin;
        switch (likeVector) {
            // normal vector is in x axis direction
            case 0:
                multiplicatorMax = (max.getX() - point.getX()) / direction.getX();
                multiplicatorMin = (min.getX() - point.getX()) / direction.getX();
                line[0] = new Vector3D(max.getX(), point.getY() + direction.getY() * multiplicatorMax, point.getZ() + direction.getZ() * multiplicatorMax);
                line[1] = new Vector3D(min.getX(), point.getY() + direction.getY() * multiplicatorMin, point.getZ() + direction.getZ() * multiplicatorMin);
                break;
            // normal vector is in y axis direction
            case 1:
                multiplicatorMax = (max.getY() - point.getY()) / direction.getY();
                multiplicatorMin = (min.getY() - point.getY()) / direction.getY();
                line[0] = new Vector3D(point.getX() + direction.getX() * multiplicatorMax, max.getY(), point.getZ() + direction.getZ() * multiplicatorMax);
                line[1] = new Vector3D(point.getX() + direction.getX() * multiplicatorMin, min.getY(), point.getZ() + direction.getZ() * multiplicatorMin);
                break;
            // normal vector is in z axis direction
            case 2:
                multiplicatorMax = (max.getZ() - point.getZ()) / direction.getZ();
                multiplicatorMin = (min.getZ() - point.getZ()) / direction.getZ();
                line[0] = new Vector3D(point.getX() + direction.getX() * multiplicatorMax, point.getY() + direction.getY() * multiplicatorMax, max.getZ());
                line[1] = new Vector3D(point.getX() + direction.getX() * multiplicatorMin, point.getY() + direction.getY() * multiplicatorMin, min.getZ());
                break;
        }
    }

    /**
     * Gives the point (variables) of the equation
     *
     * @return array of double values
     */
    @Override
    public double[] getVaraiables() {
        return new double[]{this.point.getX(), this.point.getY(), this.point.getZ(), this.direction.getX(),this.direction.getY(),this.direction.getZ()};
    }
}
